/*
 *  Copyright 2019-2020 Zheng Jie
 *
 *  Licensed under the Apache License, Version 2.0 (the "License");
 *  you may not use this file except in compliance with the License.
 *  You may obtain a copy of the License at
 *
 *  http://www.apache.org/licenses/LICENSE-2.0
 *
 *  Unless required by applicable law or agreed to in writing, software
 *  distributed under the License is distributed on an "AS IS" BASIS,
 *  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 *  See the License for the specific language governing permissions and
 *  limitations under the License.
 */
package me.zhengjie.modules.biz.service.impl;

import cn.hutool.core.convert.Convert;
import com.alibaba.fastjson.JSONObject;
import lombok.RequiredArgsConstructor;
import me.zhengjie.modules.biz.domain.*;
import me.zhengjie.modules.biz.repository.*;
import me.zhengjie.modules.biz.service.StorehouseOrderDetailService;
import me.zhengjie.modules.biz.service.dto.ReturnDto;
import me.zhengjie.modules.biz.service.dto.StorehouseOrderDetailDto;
import me.zhengjie.modules.biz.service.dto.StorehouseOrderDetailQueryCriteria;
import me.zhengjie.modules.biz.service.mapstruct.StorehouseOrderDetailMapper;
import me.zhengjie.utils.*;
import org.springframework.data.domain.Page;
import org.springframework.data.domain.Pageable;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;

import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.io.IOException;
import java.util.*;

/**
 * @author Admin
 * @website https://eladmin.vip
 * @description 服务实现
 * @date 2023-03-13
 **/
@Service
@RequiredArgsConstructor
public class StorehouseOrderDetailServiceImpl implements StorehouseOrderDetailService {

    private final StorehouseOrderDetailRepository storehouseOrderDetailRepository;
    private final StorehouseOrderRepository storehouseOrderRepository;
    private final StorehouseOrderDetailMapper storehouseOrderDetailMapper;
    private final HazardousChemicalsRepository hazardousChemicalsRepository;
    private final HazardousChemicalsTotalRepository hazardousChemicalsTotalRepository;
    private final HazardousChemicalsChangeRecordRepository HazardousChemicalsChangeRecordRepository;
    private final LabRepository labRepository;
    private final CabinetRepository cabinetRepository;

    @Override
    public Map<String, Object> queryAll(StorehouseOrderDetailQueryCriteria criteria, Pageable pageable) {
        Page<StorehouseOrderDetail> page = storehouseOrderDetailRepository.findAll((root, criteriaQuery, criteriaBuilder) -> QueryHelp.getPredicate(root, criteria, criteriaBuilder), pageable);
        return PageUtil.toPage(page.map(storehouseOrderDetailMapper::toDto));
    }

    @Override
    public List<StorehouseOrderDetailDto> queryAll(StorehouseOrderDetailQueryCriteria criteria) {
        return storehouseOrderDetailMapper.toDto(storehouseOrderDetailRepository.findAll((root, criteriaQuery, criteriaBuilder) -> QueryHelp.getPredicate(root, criteria, criteriaBuilder)));
    }

    @Override
    @Transactional
    public StorehouseOrderDetailDto findById(Integer id) {
        StorehouseOrderDetail storehouseOrderDetail = storehouseOrderDetailRepository.findById(id).orElseGet(StorehouseOrderDetail::new);
        ValidationUtil.isNull(storehouseOrderDetail.getId(), "StorehouseOrderDetail", "id", id);
        return storehouseOrderDetailMapper.toDto(storehouseOrderDetail);
    }

    @Override
    @Transactional(rollbackFor = Exception.class)
    public StorehouseOrderDetailDto create(StorehouseOrderDetail resources) {
        return storehouseOrderDetailMapper.toDto(storehouseOrderDetailRepository.save(resources));
    }

    @Override
    @Transactional(rollbackFor = Exception.class)
    public void update(StorehouseOrderDetail resources) {
        StorehouseOrderDetail storehouseOrderDetail = storehouseOrderDetailRepository.findById(resources.getId()).orElseGet(StorehouseOrderDetail::new);
        ValidationUtil.isNull(storehouseOrderDetail.getId(), "StorehouseOrderDetail", "id", resources.getId());
        storehouseOrderDetail.copy(resources);
        storehouseOrderDetailRepository.save(storehouseOrderDetail);
    }

    @Override
    public void deleteAll(Integer[] ids) {
        for (Integer id : ids) {
            storehouseOrderDetailRepository.deleteById(id);
        }
    }

    @Override
    public void download(List<StorehouseOrderDetailDto> all, HttpServletResponse response) throws IOException {
        List<Map<String, Object>> list = new ArrayList<>();
        for (StorehouseOrderDetailDto storehouseOrderDetail : all) {
            Map<String, Object> map = new LinkedHashMap<>();
            map.put(" hjHazardousChemicalId", storehouseOrderDetail.getHjHazardousChemicalId());
            map.put("数量", storehouseOrderDetail.getNumber());
            map.put("实验室ID", storehouseOrderDetail.getLabId());
            map.put("柜子ID", storehouseOrderDetail.getCabinetId());
            map.put(" createdAt", storehouseOrderDetail.getCreatedAt());
            map.put(" updatedAt", storehouseOrderDetail.getUpdatedAt());
            list.add(map);
        }
        FileUtil.downloadExcel(list, response);
    }

    @Override
    public List<StorehouseOrderDetailDto> detailList(Integer id) {
        List<String> nameList = storehouseOrderDetailRepository.findNameByOrderId(id);
        ArrayList<StorehouseOrderDetail> storehouseOrderDetailList = new ArrayList<>();
        for (String name : nameList) {
            StorehouseOrderDetail storehouseOrderDetail = storehouseOrderDetailRepository.getByNameAndOrderIdToBeApply(name, id);
            storehouseOrderDetailList.add(storehouseOrderDetail);
        }
        List<StorehouseOrderDetailDto> storehouseOrderDetailDtoList = storehouseOrderDetailMapper.toDto(storehouseOrderDetailList);
        for (StorehouseOrderDetailDto storehouseOrderDetailDto : storehouseOrderDetailDtoList) {
            HazardousChemicals hazardousChemicals = hazardousChemicalsRepository.getByNameAmount(storehouseOrderDetailDto.getName(), storehouseOrderDetailDto.getNumber());
            if (hazardousChemicals == null) {
                storehouseOrderDetailDto.setCapacity((float) 0);
            } else {
                storehouseOrderDetailDto.setCapacity(hazardousChemicals.getCapacity());
            }
        }
        return storehouseOrderDetailDtoList;
    }

    //归还
    @Override
    @Transactional(rollbackFor = Exception.class)
    public int giveBack(String data) throws Exception {
        List<ReturnDto> ReturnDtoList = JSONObject.parseArray(data, ReturnDto.class);
        for (ReturnDto returnDto : ReturnDtoList) {
            String barCode = returnDto.getBarCode().replace('h', '0');
//            barCode=barCode.replaceAll("^(0+)", "");
            int HazardousChemicalsId = Integer.parseInt(barCode);
            HazardousChemicals hazardousChemicals = hazardousChemicalsRepository.findById(HazardousChemicalsId)
                    .orElseGet(HazardousChemicals::new);
            if (!Objects.equals(hazardousChemicals.getName(), returnDto.getName())) {
                throw new Exception("试剂信息未找到");
            }

            StorehouseOrderDetail storehouseOrderDetail = storehouseOrderDetailRepository.findByHcIdToBeReturned(HazardousChemicalsId);
            if (storehouseOrderDetail == null) {
                throw new Exception("试剂" + hazardousChemicals.getName() + "-id:" + hazardousChemicals.getId() + " 未被领用，不需要归还");
            }

            float detailNumber = 0;
            if (hazardousChemicals.isQiCai()) {//器材
                if (hazardousChemicals.getResidue() == 0) {//剩余量
                    hazardousChemicals.setStatus(0);
                    hazardousChemicals.setResidue(1f);
                    hazardousChemicalsRepository.save(hazardousChemicals);
                    HazardousChemicalsTotal hazardousChemicalsTotal = hazardousChemicalsTotalRepository
                            .findByNameAndBatchNumber(hazardousChemicals.getName(), hazardousChemicals.getBatchNumber());
                    if (hazardousChemicalsTotal == null) {//全部出库，重新加数据
                        HazardousChemicalsTotal hazardousChemicalsTotal1 = new HazardousChemicalsTotal();
                        hazardousChemicalsTotal1.setTotalNumber(1);
                        hazardousChemicalsTotal1.setUnit(hazardousChemicals.getUnit());
                        hazardousChemicalsTotal1.setIsAudit(hazardousChemicals.getIsAudit());
                        hazardousChemicalsTotal1.setGross(1f);
                        hazardousChemicalsTotal1.setAmount(hazardousChemicals.getAmount());
                        hazardousChemicalsTotal1.setCategory(hazardousChemicals.getCategory());
                        hazardousChemicalsTotal1.setCountType(hazardousChemicals.getCountType());
                        hazardousChemicalsTotal1.setStorage(hazardousChemicals.getStorage());
                        hazardousChemicalsTotal1.setDangerClasses(hazardousChemicals.getDangerClasses());
                        hazardousChemicalsTotal1.setType(hazardousChemicals.getType());
                        hazardousChemicalsTotal1.setName(hazardousChemicals.getName());
                        hazardousChemicalsTotal1.setLabId(hazardousChemicals.getLabId());
                        hazardousChemicalsTotal1.setCabinetId(hazardousChemicals.getCabinetId());
                        hazardousChemicalsTotalRepository.save(hazardousChemicalsTotal1);
                    } else {//部分出库，归还
                        hazardousChemicalsTotal.setTotalNumber(hazardousChemicalsTotal.getTotalNumber() + 1);
                        hazardousChemicalsTotalRepository.save(hazardousChemicalsTotal);
                    }

                    detailNumber = 1;
                    HazardousChemicalsChangeRecord hazardousChemicalsChangeRecord = new HazardousChemicalsChangeRecord();
                    hazardousChemicalsChangeRecord.setOrderId(storehouseOrderDetail.getOrderId());
                    hazardousChemicalsChangeRecord.setUserId(Convert.toInt(SecurityUtils.getCurrentUserId()));
                    hazardousChemicalsChangeRecord.setDetailNumber(1f);
                    hazardousChemicalsChangeRecord.setType(hazardousChemicals.getType());
                    hazardousChemicalsChangeRecord.setName(hazardousChemicals.getName());
                    hazardousChemicalsChangeRecord.setAmount(1f);
                    hazardousChemicalsChangeRecord.setCountType(hazardousChemicals.getCountType());
                    hazardousChemicalsChangeRecord.setHcId(hazardousChemicals.getId());
                    hazardousChemicalsChangeRecord.setState(HazardousChemicalsChangeRecord.STATE_GIVE_BACK);
                    HazardousChemicalsChangeRecordRepository.save(hazardousChemicalsChangeRecord);
                } else {
                    throw new RuntimeException("二维码输入错误");
                }
            } else {//标准物质和化学试剂归还逻辑相同
                hazardousChemicals.setStatus(0);
                hazardousChemicals.setResidue(returnDto.getRealNum());//设置剩余量
                hazardousChemicalsRepository.save(hazardousChemicals);

                HazardousChemicalsTotal hazardousChemicalsTotal;

                if (hazardousChemicals.isBiaoZhunWuZhi()) {
                    hazardousChemicalsTotal = hazardousChemicalsTotalRepository
                            .findByNameAndBatchNumber(hazardousChemicals.getName(), hazardousChemicals.getBatchNumber());
                } else {
                    hazardousChemicalsTotal = hazardousChemicalsTotalRepository
                            .findByNameAndType(hazardousChemicals.getName(), hazardousChemicals.getType());
                }

                if (hazardousChemicalsTotal == null) {
                    HazardousChemicalsTotal hazardousChemicalsTotal1 = new HazardousChemicalsTotal();
                    hazardousChemicalsTotal1.setTotalNumber(returnDto.getRealNum());
                    hazardousChemicalsTotal1.setUnit(hazardousChemicals.getUnit());
                    hazardousChemicalsTotal1.setIsAudit(hazardousChemicals.getIsAudit());
                    hazardousChemicalsTotal1.setGross(returnDto.getRealNum());
                    hazardousChemicalsTotal1.setAmount(hazardousChemicals.getAmount());
                    hazardousChemicalsTotal1.setCategory(hazardousChemicals.getCategory());
                    hazardousChemicalsTotal1.setCountType(hazardousChemicals.getCountType());
                    hazardousChemicalsTotal1.setStorage(hazardousChemicals.getStorage());
                    hazardousChemicalsTotal1.setDangerClasses(hazardousChemicals.getDangerClasses());
                    hazardousChemicalsTotal1.setType(hazardousChemicals.getType());
                    hazardousChemicalsTotal1.setName(hazardousChemicals.getName());
                    hazardousChemicalsTotal1.setLabId(hazardousChemicals.getLabId());
                    hazardousChemicalsTotal1.setCabinetId(hazardousChemicals.getCabinetId());
                    hazardousChemicalsTotalRepository.save(hazardousChemicalsTotal1);
                } else {
                    hazardousChemicalsTotal.setTotalNumber(hazardousChemicalsTotal.getTotalNumber() + returnDto.getRealNum());
                    hazardousChemicalsTotalRepository.save(hazardousChemicalsTotal);
                }

                if (returnDto.getRealNum() > storehouseOrderDetail.getClaimDetailNumber()) {
                    throw new Exception("归还数量" + returnDto.getRealNum() + "不能大于领用数量" + storehouseOrderDetail.getClaimDetailNumber());
                }

                detailNumber = returnDto.getRealNum();
                HazardousChemicalsChangeRecord hazardousChemicalsChangeRecord = new HazardousChemicalsChangeRecord();
                hazardousChemicalsChangeRecord.setOrderId(storehouseOrderDetail.getOrderId());
                hazardousChemicalsChangeRecord.setUserId(Convert.toInt(SecurityUtils.getCurrentUserId()));
                hazardousChemicalsChangeRecord.setDetailNumber(returnDto.getRealNum());
                hazardousChemicalsChangeRecord.setCountType(hazardousChemicals.getCountType());
                hazardousChemicalsChangeRecord.setType(hazardousChemicals.getType());
                hazardousChemicalsChangeRecord.setName(hazardousChemicals.getName());

                hazardousChemicalsChangeRecord.setBatchNumber(hazardousChemicals.getBatchNumber());
                hazardousChemicalsChangeRecord.setNumber(hazardousChemicals.getNumber());//编号
                hazardousChemicalsChangeRecord.setIngredientData(hazardousChemicals.getIngredientData());
                hazardousChemicalsChangeRecord.setMatrix(hazardousChemicals.getMatrix());
                hazardousChemicalsChangeRecord.setExpirationDate(hazardousChemicals.getExpirationDate());


                if (hazardousChemicals.isSingleCodePerObject()) {//一物一码
                    hazardousChemicalsChangeRecord.setAmount(1f);
                } else {//
                    hazardousChemicalsChangeRecord.setAmount(returnDto.getRealNum());
                }

                hazardousChemicalsChangeRecord.setHcId(hazardousChemicals.getId());
                hazardousChemicalsChangeRecord.setState(HazardousChemicalsChangeRecord.STATE_GIVE_BACK);

                HazardousChemicalsChangeRecordRepository.save(hazardousChemicalsChangeRecord);
            }

            //设置归还状态
            storehouseOrderDetail.setStatus(6);
            storehouseOrderDetail.setReturnDetailNumber(detailNumber);
//                storehouseOrderDetail.setHjHazardousChemicalId(null);
            storehouseOrderDetailRepository.save(storehouseOrderDetail);

            //判断同一个订单下面的试剂是否都已经归还，如果都已经归还，则更新订单状态
            List<StorehouseOrderDetail> storehouseOrderDetails = storehouseOrderDetailRepository.findByOrderId(storehouseOrderDetail.getOrderId());

            boolean isAllReturned = true;
            for (int i = 0; i < storehouseOrderDetails.size(); i++) {
                if (storehouseOrderDetails.get(i).getStatus() == 5) {
                    isAllReturned = false;
                }
            }
            if (isAllReturned) {
                //修改订单状态
                StorehouseOrder order = storehouseOrderRepository.getById(storehouseOrderDetail.getOrderId());
                order.setStatus(6);
                storehouseOrderRepository.save(order);
            }
        }
        return 0;
    }

    @Override
    public Map<String, Object> returnList(HttpServletRequest request) {

        int page = Integer.parseInt(request.getParameter("page"));
        int size = Integer.parseInt(request.getParameter("size"));
        int real_page = page * size;
//        int real_size = real_page + size;
        int real_size = size;
        Map<String, Object> totalMap = new HashMap<String, Object>();
        List<StorehouseOrderDetail> storehouseOrderDetailList;
        Long userId = SecurityUtils.getCurrentUserId();

        float total = 0;
        List<StorehouseOrderDetail> countList;
        // status  5:待归还  6:已归还
        if (request.getParameter("name") == null && request.getParameter("status") == null) {
            storehouseOrderDetailList = storehouseOrderDetailRepository.findOrderDetail(userId, real_page, real_size);
//            total = storehouseOrderDetailRepository.countOrderDetail(userId).getNumber();
            countList = storehouseOrderDetailRepository.findOrderDetail(userId, 0, 1000000000);
        } else if (request.getParameter("name") != null && request.getParameter("status") == null) {
            storehouseOrderDetailList = storehouseOrderDetailRepository.findOrderDetailByName(request.getParameter("name"), userId, real_page, real_size);
//            total = storehouseOrderDetailRepository.countOrderDetailByName(request.getParameter("name"), userId);
            countList = storehouseOrderDetailRepository.findOrderDetailByName(request.getParameter("name"), userId, 0, 1000000000);
        } else if (request.getParameter("name") == null && request.getParameter("status") != null) {
            storehouseOrderDetailList = storehouseOrderDetailRepository.findOrderDetailByStatus(request.getParameter("status"), userId, real_page, real_size);
//            total = storehouseOrderDetailRepository.countOrderDetailByStatus(request.getParameter("status"), userId);
            countList = storehouseOrderDetailRepository.findOrderDetailByStatus(request.getParameter("status"), userId, 0, 1000000000);
        } else {
            storehouseOrderDetailList = storehouseOrderDetailRepository.findOrderDetailByNameAndStatus(request.getParameter("name"), request.getParameter("status"), userId, real_page, real_size);
//            total = storehouseOrderDetailRepository.countOrderDetailByNameAndStatus(request.getParameter("name"), request.getParameter("status"), userId);
            countList = storehouseOrderDetailRepository.findOrderDetailByNameAndStatus(request.getParameter("name"), request.getParameter("status"), userId, 0, 1000000000);
        }
        List<StorehouseOrderDetailDto> storehouseOrderDetailDtoList = storehouseOrderDetailMapper.toDto(storehouseOrderDetailList);
        for (StorehouseOrderDetailDto storehouseOrderDetailDto : storehouseOrderDetailDtoList) {
            if (storehouseOrderDetailDto.getCategory() == null) {
                storehouseOrderDetailDto.setApplyNum(
                        storehouseOrderDetailRepository.sum(
                                storehouseOrderDetailDto.getName(),
                                storehouseOrderDetailDto.getType(),
                                storehouseOrderDetailDto.getStatus(),
                                userId
                        )
                );
            } else {
                storehouseOrderDetailDto.setApplyNum(
                        storehouseOrderDetailRepository.sum(
                                storehouseOrderDetailDto.getName(),
                                storehouseOrderDetailDto.getCategory(),
                                storehouseOrderDetailDto.getType(),
                                storehouseOrderDetailDto.getStatus(),
                                userId
                        )
                );
            }

        }

        totalMap.put("content", storehouseOrderDetailDtoList);
        totalMap.put("totalElements", countList.size());

        return totalMap;
    }

    //查询已归还数据
    @Override
    public List<StorehouseOrderDetailDto> returnedList(HttpServletRequest request) {
        String[] cabinetList = request.getParameter("cabinetIds").split(",");
        int[] cabinetIdList = new int[cabinetList.length];
        for (int i = 0; i < cabinetList.length; i++) {
            cabinetIdList[i] = Integer.parseInt(cabinetList[i]);
        }
        List<StorehouseOrderDetail> storehouseOrderDetailList = storehouseOrderDetailRepository
                .findOrderDetailByStatusCabinetIdList(6, cabinetIdList);
        List<StorehouseOrderDetailDto> storehouseOrderDetailDtoList = storehouseOrderDetailMapper.toDto(storehouseOrderDetailList);
        extendsStorehouseOrderDetailDto(storehouseOrderDetailDtoList);
        return storehouseOrderDetailDtoList;
    }

    //查询未归还数据
    @Override
    public List<StorehouseOrderDetailDto> noReturnedList(HttpServletRequest request) {
        String[] cabinetList = request.getParameter("cabinetIds").split(",");
        int[] cabinetIdList = new int[cabinetList.length];
        for (int i = 0; i < cabinetList.length; i++) {
            cabinetIdList[i] = Integer.parseInt(cabinetList[i]);
        }
        List<StorehouseOrderDetail> storehouseOrderDetailList = storehouseOrderDetailRepository.findOrderDetailByStatusCabinetIdList(5, cabinetIdList);
        List<StorehouseOrderDetailDto> storehouseOrderDetailDtoList = storehouseOrderDetailMapper.toDto(storehouseOrderDetailList);

        extendsStorehouseOrderDetailDto(storehouseOrderDetailDtoList);
        return storehouseOrderDetailDtoList;
    }

    @Override
    public List<StorehouseOrder> findByUserIdAndStatus(Integer userId, int status) {
        return storehouseOrderRepository.findByUserIdAndStatus(userId, status);
    }

    void extendsStorehouseOrderDetailDto(List<StorehouseOrderDetailDto> storehouseOrderDetailDtoList) {
        List<Integer> labIds = new ArrayList<>();
        List<Integer> cabinetIds = new ArrayList<>();

        for (StorehouseOrderDetailDto storehouseOrderDetailDto : storehouseOrderDetailDtoList) {
            labIds.add(storehouseOrderDetailDto.getLabId());
            cabinetIds.add(storehouseOrderDetailDto.getCabinetId());
        }

        Map<Integer, Lab> labIdToLab = new HashMap<>();
        List<Lab> labs = labRepository.findAll();
        for (Lab lab : labs) {
            labIdToLab.put(lab.getId(), lab);
        }

        Map<Integer, Cabinet> cabinetIdToCabinets = new HashMap<>();
        List<Cabinet> cabinets = cabinetRepository.findAll();
        for (Cabinet cabinet : cabinets) {
            cabinetIdToCabinets.put(cabinet.getId(), cabinet);
        }

        for (StorehouseOrderDetailDto storehouseOrderDetailDto : storehouseOrderDetailDtoList) {
            storehouseOrderDetailDto.setReturnDetailNumber(0f);
            if (labIdToLab.containsKey(storehouseOrderDetailDto.getLabId())) {
                storehouseOrderDetailDto.setLabName(
                        labIdToLab.get(storehouseOrderDetailDto.getLabId()).getName()
                );
            }
            if (cabinetIdToCabinets.containsKey(storehouseOrderDetailDto.getCabinetId())) {
                storehouseOrderDetailDto.setCabinetName(
                        cabinetIdToCabinets.get(storehouseOrderDetailDto.getCabinetId()).getName()
                );
            } else {
                storehouseOrderDetailDto.setCabinetName(
                        "未知"
                );
            }
        }
    }

}
